package com.timing.finder.framework;

import lombok.extern.slf4j.Slf4j;

/**
 * 时序数据应用启动引导器
 *
 * @author JingGe(* ^ ▽ ^ *)
 * @date 2023-03-03 16:30
 * @email 1158055613@qq.com
 */
@Slf4j
public class TimingFinderBootstrap<T extends TimeSeriesData> {
    private final TimingFinderApplication<T> application;

    private final TimingFinderConfigFactory configFactory;

    private final DBRepository<T> dbRepository;

    private final HandleType handleType;

    private String configSuffix;


    public TimingFinderBootstrap(TimingFinderConfigFactory configFactory, DBRepository<T> dbRepository, HandleType handleType) {
        if (handleType == null || handleType.getCacheDataType() == null || handleType.getTimeSeriesDataType() == null) {
            throw new NullPointerException("type不能为null");
        }
        application = new TimingFinderApplication<>();
        this.handleType = handleType;
        this.configFactory = configFactory;
        this.dbRepository = dbRepository;
        this.configSuffix = handleType
                .getTimeSeriesDataType()
                .getSimpleName();

    }

    public TimingFinderBootstrap(DBRepository<T> dbRepository, HandleType handleType) {
        this(new YamlConfigFactory(), dbRepository, handleType);
    }

    public TimingFinderBootstrap<T> setLoader(TimeSeriesDataLoader<T> loader) {
        application.loader = loader;
        return this;
    }

    public TimingFinderBootstrap<T> setHandler(TimeSeriesDataHandler<T> handler) {
        application.handler = handler;
        return this;
    }

    public TimingFinderBootstrap<T> setLoadTimingJob(DataLoadTimingJob loadTimingJob) {
        application.loadTimingJob = loadTimingJob;
        return this;
    }

    public TimingFinderBootstrap<T> setConfigSuffix(String name) {
        this.configSuffix = name;
        return this;
    }

    private <R> R choseWhenNull(R o1, R orElse) {
        return o1 == null ? orElse : o1;
    }

    public TimingFinderApplication<T> build() {
        application.handleType = this.handleType;
        application.configFactory = this.configFactory;
        application.config = configFactory.create(configSuffix);
        application.applicationName = application.config.applicationName;
        application.dbRepository = this.dbRepository;
        application.loader = choseWhenNull(application.loader, new DefaultTimeSeriesDataLoader<>(dbRepository, application.config));
        application.handler = choseWhenNull(application.handler, new DefaultTimeSeriesDataHandler<>(application.config));
        application.loadTimingJob = choseWhenNull(application.loadTimingJob, new YamlConfigTimingJob<>(application.config, application.loader, application.handler));
        if (application.config.enableLoader) {
            if (!application.config.clearBeforeRun && StorableBloomFilter.isInCache(application.handler.cacheRepository(), application.applicationName)) {
                log.info("从缓存中加载应用{}已有的布隆过滤器", application.applicationName);
                application.bloomFilter = StorableBloomFilter.loadFromCache(application.handler.cacheRepository(), application.config);
            } else {
                log.info("创建应用{}新的布隆过滤器", application.applicationName);
                application.bloomFilter = new StorableBloomFilter(application.config, application.handler.cacheRepository());
            }
            BloomFilterContainer
                    .getInstance()
                    .putNewBloomFilter(application.applicationName, application.bloomFilter);
        }
        return application;
    }


}
